import requests
from flask import request, jsonify, current_app, g

from apps.apis import api
from apps.core.auth import verify_json_schema, verify_token_auth
from apps.core.database import db
from apps.core.mwebhdfs import change_hdfs
from apps.core.schemaall import move_file_schema, validation_filename_schema, file_get_log_schema, get_dir_files_schema
from apps.logger.web_logger import weblog
from apps.models import LogUser
from apps.utils.return_info import ReturnInfo


@api.route("/files/validation_filename", methods=['POST'])
@verify_json_schema(validation_filename_schema)
@verify_token_auth(allowtokennull=False)
def validation_filename():
    """
    验证文件名在目标目录是否存在
    由于/files/uploads_file接口需要上传完成才能执行判断是否存在的逻辑,
    对大文件来说对网络开销太大且无意义，所以先执行验证,在上传
    ---
    tags:
      - files
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          properties:
            token:
              type: string
              description: token.
              example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
            types:
              type: string
              description: meta or ref
              example: meta
            filenames:
              type: array
              description: 文件名的列表
              example: ['a.db3','b.db3']
              item:
                type:string
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
    consumes:
      - application/json
    produces:
      - application/json
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"文件移动成功","data":[]}
    :return:
    """
    ret_obj = ReturnInfo()
    jsons = request.json
    types = jsons.get("types")
    filenames = jsons.get("filenames")

    for item in filenames:
        if not item.endswith(".db3"):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "文件{}不是db3文件".format(item)
            return jsonify(ret_obj.todict())

    web_hdfs_uri = current_app.config.get("WEB_HDFS")
    DES_DIR_BASE = current_app.config.get("DES_DIR_BASE")

    kwargs = {}
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "CREATE"
    kwargs["overwrite"] = False
    requests_session = requests.api

    list_dest = []
    response = ""
    try:
        kwargs["op"] = "LISTSTATUS"
        response = requests_session.request("get",
                                            "{}{}{}".format(web_hdfs_uri, DES_DIR_BASE, types),
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if change_hdfs(response):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "webhdfs 已切换,请重新访问"
            ret_obj.data = {}
            return jsonify(ret_obj.todict())

        for item in response.json()["FileStatuses"]["FileStatus"]:
            if item["pathSuffix"].endswith(".db3"):
                list_dest.append(item["pathSuffix"])
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "查询{}目录错误".format("{}{}{}".format(web_hdfs_uri, DES_DIR_BASE, types))
        ret_obj.data = {"errmsg": str(e), "result": response.json()}
        return jsonify(ret_obj.todict())

    is_have_db3 = set(filenames) & set(list_dest)
    if len(is_have_db3) > 0:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "{}{}目录中存在文件 {}".format(DES_DIR_BASE, types, is_have_db3)
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())

    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "验证通过"
    return jsonify(ret_obj.todict())


@api.route("/files/upload_files", methods=['POST'])
@verify_token_auth(allowtokennull=False)
# @func_line_time
def upload_files():
    """
    文件上传
    由于flagger没有支持多文件上传 我在 /test_up_file 路由下写了个简单的
    多文件上传测试接口
    ---
    tags:
      - files
    consumes:
      - multipart/form-data
    produces:
      - application/json
    parameters:
      - name: token
        in: formData
        description: token值
        type: string
        required: true
      - name: files
        in: formData
        description: 上传的文件
        type: file
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"文件上传成功","data":[]}
    :return:
    """
    # Flask处理文件上传的方式 如果上传的文件很小，那么会把它直接存在内存中。
    # 否则就会把它保存到一个临时目录下，
    # 通过tempfile.gettempdir()方法可以获取这个临时目录的位置。
    # print(tempfile.gettempdir())
    ret_obj = ReturnInfo()

    web_hdfs_uri = current_app.config.get("WEB_HDFS")
    TEMP_DES_DIR_BASE = current_app.config.get("TEMP_DES_DIR_BASE")

    files = request.files.getlist("files")
    # 临时目录为
    temp_dir = web_hdfs_uri + TEMP_DES_DIR_BASE + "/" + str(g.user.userid)
    # 查看目录
    ret_obj.msg_code = "FAILED"

    kwargs = {}
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "GETFILESTATUS"

    requests_session = requests.api
    response = requests_session.request("get",
                                        temp_dir,
                                        params=kwargs,
                                        timeout=30,
                                        allow_redirects=False)
    if change_hdfs(response):
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "webhdfs 已切换,请重新访问"
        ret_obj.data = {}
        return jsonify(ret_obj.todict())

    if "RemoteException" in response.json():
        weblog.info(g.weblog_id + ";不存在目录,创建目录")
        kwargs["op"] = "MKDIRS"
        kwargs["permission"] = "775"
        response = requests_session.request("put",
                                            temp_dir,
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if "boolean" in response.json() and response.json()["boolean"]:
            weblog.info(g.weblog_id + ";不存在目录,创建目录成功")
        else:
            weblog.info(g.weblog_id + ";不存在目录,创建目录失败")
            ret_obj.msg = "不存在目录,创建目录失败"
            return jsonify(ret_obj.todict())
    else:
        weblog.info(g.weblog_id + ";存在目录,删除目录里的文件")
        kwargs["op"] = "DELETE"
        kwargs["recursive"] = True
        response = requests_session.request("delete",
                                            temp_dir,
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if "boolean" in response.json() and response.json()["boolean"]:
            weblog.info(g.weblog_id + ";存在目录,删除目录及里面的文件成功")
        else:
            weblog.info(g.weblog_id + ";存在目录,删除目录及里面的文件失败")
            ret_obj.msg = "存在目录,删除目录及里面的文件失败"
            return jsonify(ret_obj.todict())
        kwargs["op"] = "MKDIRS"
        kwargs["permission"] = "775"
        response = requests_session.request("put",
                                            temp_dir,
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if "boolean" in response.json() and response.json()["boolean"]:
            weblog.info(g.weblog_id + ";存在目录,删除后创建目录成功")
        else:
            weblog.info(g.weblog_id + ";存在目录,删除后创建目录失败")
            ret_obj.msg = "存在目录,删除后创建目录失败"
            return jsonify(ret_obj.todict())

    requests_session = requests.api
    kwargs = {}
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "CREATE"
    kwargs["overwrite"] = False
    is_all_true = True
    try:
        lists_boolean_false = []
        lists_boolean_true = []
        file_num = len(files)
        allsize = 0
        for onefile in files:
            if onefile.filename:
                if onefile.filename.endswith(".db3"):
                    size = len(onefile.read())
                    onefile.seek(0, 0)
                    allsize = allsize + size
                    filename = onefile.filename
                    kwargs["op"] = "CREATE"
                    kwargs["permission"] = "775"
                    response = requests_session.request("put",
                                                        "{}/{}".format(temp_dir, filename),
                                                        params=kwargs,
                                                        timeout=30,
                                                        allow_redirects=False)
                    # 正常状态码 307
                    if response.status_code == 307:
                        response = requests_session.put(response.headers['location'], data=onefile)
                        # 第二次请求正常状态码 201
                        if response.status_code == 201:
                            lists_boolean_true.append({"name": onefile.filename, "size": size})
                        else:

                            is_all_true = False
                            lists_boolean_false.append({"step1": "success",
                                                        "step2": "状态码:{}".format(response.status_code),
                                                        "size": size})
                    else:
                        is_all_true = False
                        lists_boolean_false.append({"step1": "状态码:{}".format(response.status_code),
                                                    "size": size})
        log_json = {"source_dir": temp_dir,
                    "file_num": file_num,
                    "allsize": allsize,
                    "success_up": lists_boolean_true,
                    "failed_up": lists_boolean_false
                    }
        if is_all_true:
            ret_obj.msg_code = "SUCCESS"
            ret_obj.msg = "上传到临时目录{}成功".format(temp_dir)
            ret_obj.data = {"result": log_json}
        else:
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "上传到临时目录{}失败,有可能部分成功，详细信息查看errmsg".format(temp_dir)
            ret_obj.data = {"errmsg": log_json}
    except Exception as e:
        # 远程主机强迫关闭了一个现有的连接。 可能是账号无此目录权限
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "上传临时目录{}目录失败,请查看捕获的错误信息".format(temp_dir)
        ret_obj.data = {"errmsg": str(e)}
        return jsonify(ret_obj.todict())

    return jsonify(ret_obj.todict())


@api.route("/files/sure_upload_files", methods=['POST'])
@verify_token_auth(allowtokennull=False)
def sure_upload_files():
    """
       确认上传文件
       ---
       tags:
         - files
       parameters:
         - in: body
           name: body
           required: true
           description: JSON 参数.
           schema:
             properties:
               token:
                 type: string
                 description: token.
                 example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
               types:
                 type: string
                 description: meta or ref
                 example: meta
               explain:
                 type: string
                 description: 加入说明性文字
                 example: 上传原因
       definitions:
         ReturnInfo:
           type: object
           properties:
             msg_code:
               type: string
               description: SUCCESS 或者 FAILED.
               example: SUCCESS
             msg:
               type: string
               description: 说明文字，帮助找到失败原因
               example: 不能使用get请求
             data:
               type: object
               description: 返回的信息全部在data中获取
       consumes:
         - application/json
       produces:
         - application/json
       responses:
         200:
           description: OK.
           schema:
             $ref: '#/definitions/ReturnInfo'
           examples:
             returninfo: {"msg_code":"SUCCESS","msg":"文件移动成功","data":[]}
       :return:
       """
    ret_obj = ReturnInfo()
    jsons = request.json
    types = jsons.get("types")
    explain = jsons.get("explain")
    web_hdfs_uri = current_app.config.get("WEB_HDFS")
    DES_DIR_BASE = current_app.config.get("DES_DIR_BASE")
    TEMP_DES_DIR_BASE = current_app.config.get("TEMP_DES_DIR_BASE")
    source_dir = web_hdfs_uri + TEMP_DES_DIR_BASE + "/" + str(g.user.userid)
    kwargs = {}
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "CREATE"
    kwargs["overwrite"] = False
    requests_session = requests.api
    response = ""
    # list_source = []
    list_source_complete = []
    try:
        kwargs["op"] = "LISTSTATUS"
        response = requests_session.request("get",
                                            source_dir,
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if change_hdfs(response):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "webhdfs 已切换,请重新访问"
            ret_obj.data = {}
            return jsonify(ret_obj.todict())
        for item in response.json()["FileStatuses"]["FileStatus"]:
            if item["pathSuffix"].endswith(".db3"):
                # list_source.append(item["pathSuffix"])
                list_source_complete.append((item["pathSuffix"], item["length"]))
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "临时目录错误,不存在或不是一个目录"
        ret_obj.data = {"errmsg": str(e), "result": jsons}
        return jsonify(ret_obj.todict())
    if not list_source_complete:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "临时目录下没有db3文件,上传出错"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())

    response = ""
    allsize = 0
    for db3name, size in list_source_complete:
        allsize = allsize + size
    file_num = len(list_source_complete)
    try:
        lists_boolean_false = []
        lists_boolean_true = []
        for db3name, size in list_source_complete:
            kwargs["op"] = "RENAME"
            kwargs["destination"] = "{}{}/{}".format(DES_DIR_BASE, types, db3name)
            response = requests_session.request("put",
                                                '{}/{}'.format(source_dir, db3name),
                                                params=kwargs,
                                                timeout=30,
                                                allow_redirects=False)
            if not response.json()["boolean"]:
                lists_boolean_false.append({"name": db3name, "size": size})
            else:
                lists_boolean_true.append({"name": db3name, "size": size})
        if len(lists_boolean_false) > 0:
            log_json = {"source_dir": "{}{}".format(DES_DIR_BASE, types),
                        "allsize": allsize,
                        "explain": explain,
                        "file_num": file_num,
                        "success_up": lists_boolean_true,
                        "failed_up": lists_boolean_false}

            loguser = LogUser(userid=g.user.userid,
                              username=g.user.username,
                              ip=request.remote_addr,
                              log_type=2,
                              log_json=log_json)
            loguser.set_file_type_int(types)
            try:
                db.session.add(loguser)
                db.session.commit()
            except Exception as e:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "日志数据写入数据库失败,部分文件移动成功"
                ret_obj.data = {"errmsg": str(e), "log_json": log_json}
                return jsonify(ret_obj.todict())

            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "移动文件部分出错,一般文件存在会报该错误"
            ret_obj.data = {"errmsg": {"success_move": lists_boolean_true, "failed_move": lists_boolean_false}}
            return jsonify(ret_obj.todict())
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "移动文件出错,请查看errmsg查找错误原因"
        ret_obj.data = {"errmsg": str(e), "result": response.json()}
        return jsonify(ret_obj.todict())

    log_json = {"source_dir": "{}{}".format(DES_DIR_BASE, types),
                "allsize": allsize,
                "explain": explain,
                "file_num": file_num,
                "success_up": lists_boolean_true,
                "failed_up": lists_boolean_false}

    loguser = LogUser(userid=g.user.userid,
                      username=g.user.username,
                      ip=request.remote_addr,
                      log_type=2,
                      log_json=log_json)
    loguser.set_file_type_int(types)
    try:
        db.session.add(loguser)
        db.session.commit()
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "日志数据写入数据库失败,但移动已经成功"
        ret_obj.data = {"errmsg": str(e)}
        return jsonify(ret_obj.todict())
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "移动成功"
    ret_obj.data = {"result": log_json}
    return jsonify(ret_obj.todict())


@api.route("/files/move_files", methods=['POST'])
@verify_json_schema(move_file_schema)
@verify_token_auth(allowtokennull=False)
def move_file():
    """
    移动文件,将source_dir 移动到/RawData/_base_obj_db3下的meta或者ref
    ---
    tags:
      - files
    consumes:
      - application/json
    produces:
      - application/json
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          properties:
            token:
              type: string
              description: token.
              example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
            types:
              type: string
              description: meta or ref
              example: meta
            explain:
              type: string
              description: 加入说明性文字
              example: 移动的目的
            source_dir:
              type: string
              description: 将要移动的目录，该目录下的db3文件将被移动到/RawData/_base_obj_db3/meta or /RawData/_base_obj_db3/ref 中去
              example: /RawData/_test/db3
            filenames:
              type: array
              description: 将要移动的目录下的db3文件列表
              example: ['a.db3','b.db3']
              items:
                type: string
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"文件移动成功","data":[]}
    :return:
    """
    ret_obj = ReturnInfo()
    jsons = request.json
    types = jsons.get("types")
    explain = jsons.get("explain")
    filenames = jsons.get("filenames")
    source_dir = jsons.get("source_dir")
    source_dir = source_dir.rstrip("/")
    # files_type_dicts = {"meta": 1, "ref": 2}

    list_err_filenames = [x for x in filenames if not x.endswith(".db3")]
    if list_err_filenames:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "列表中包含不以db3结尾的文件，请检查"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())

    kwargs = {}
    web_hdfs_uri = current_app.config.get("WEB_HDFS")
    DES_DIR_BASE = current_app.config.get("DES_DIR_BASE")
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "CREATE"
    kwargs["overwrite"] = False
    requests_session = requests.api
    response = ""
    list_source = []
    list_source_complete = []
    dicts_source_complete = {}
    try:
        kwargs["op"] = "LISTSTATUS"
        response = requests_session.request("get",
                                            '{}{}'.format(web_hdfs_uri, source_dir),
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        if change_hdfs(response):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "webhdfs 已切换,请重新访问"
            ret_obj.data = {}
            return jsonify(ret_obj.todict())

        for item in response.json()["FileStatuses"]["FileStatus"]:
            if item["pathSuffix"].endswith(".db3"):
                list_source.append(item["pathSuffix"])
                # list_source_complete.append((item["pathSuffix"], item["length"]))
                dicts_source_complete[item["pathSuffix"]] = (item["pathSuffix"], item["length"])
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "需要移动的目录错误,不存在或不是一个目录"
        ret_obj.data = {"errmsg": str(e), "result": jsons}
        return jsonify(ret_obj.todict())
    if not list_source:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "目录下没有db3文件"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    list_dest = []
    try:
        kwargs["op"] = "LISTSTATUS"
        response = requests_session.request("get",
                                            "{}{}{}".format(web_hdfs_uri, DES_DIR_BASE, types),
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)

        for item in response.json()["FileStatuses"]["FileStatus"]:
            if item["pathSuffix"].endswith(".db3"):
                list_dest.append(item["pathSuffix"])
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "查询{}目录错误".format("{}{}{}".format(web_hdfs_uri, DES_DIR_BASE, types))
        ret_obj.data = {"errmsg": str(e), "result": jsons}
        return jsonify(ret_obj.todict())

    is_have_db3 = set(set(list_source) & set(filenames)) & set(list_dest)
    if len(is_have_db3) > 0:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "{}{}目录中存在文件 {}".format(DES_DIR_BASE, types, is_have_db3)
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    response = ""
    allsize = 0
    list_source_complete = [dicts_source_complete[x] for x in filenames]
    for db3name, size in list_source_complete:
        allsize = allsize + size
    file_num = len(list_source)
    try:
        lists_boolean_false = []
        lists_boolean_true = []
        for db3name, size in list_source_complete:
            kwargs["op"] = "RENAME"
            kwargs["destination"] = "{}{}/{}".format(DES_DIR_BASE, types, db3name)
            response = requests_session.request("put",
                                                '{}{}/{}'.format(web_hdfs_uri, source_dir, db3name),
                                                params=kwargs,
                                                timeout=30,
                                                allow_redirects=False)
            if not response.json()["boolean"]:
                lists_boolean_false.append({"name": db3name, "size": size})
            else:
                lists_boolean_true.append({"name": db3name, "size": size})
        if len(lists_boolean_false) > 0:
            log_json = {"source_dir": source_dir,
                        "destination": "{}{}".format(DES_DIR_BASE, types),
                        "allsize": allsize,
                        "explain": explain,
                        "file_num": file_num,
                        "success_move": lists_boolean_true,
                        "failed_move": lists_boolean_false}

            loguser = LogUser(userid=g.user.userid,
                              username=g.user.username,
                              ip=request.remote_addr,
                              log_type=3,
                              log_json=log_json)
            loguser.set_file_type_int(types)
            try:
                db.session.add(loguser)
                db.session.commit()
            except Exception as e:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "日志数据写入数据库失败,部分文件移动成功"
                ret_obj.data = {"errmsg": str(e), "log_json": log_json}
                return jsonify(ret_obj.todict())

            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "移动文件部分出错,一般文件存在会报该错误"
            ret_obj.data = {"errmsg": {"success_move": lists_boolean_true, "failed_move": lists_boolean_false}}
            return jsonify(ret_obj.todict())
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "移动文件出错,请查看errmsg查找错误原因"
        ret_obj.data = {"errmsg": str(e), "result": response.json()}
        return jsonify(ret_obj.todict())

    log_json = {"source_dir": source_dir,
                "destination": "{}{}".format(DES_DIR_BASE, types),
                "allsize": allsize,
                "explain": explain,
                "file_num": file_num,
                "success_move": lists_boolean_true,
                "failed_move": lists_boolean_false}

    loguser = LogUser(userid=g.user.userid,
                      username=g.user.username,
                      ip=request.remote_addr,
                      log_type=3,
                      log_json=log_json)
    loguser.set_file_type_int(types)
    try:
        db.session.add(loguser)
        db.session.commit()
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "日志数据写入数据库失败,但移动已经成功"
        ret_obj.data = {"errmsg": str(e)}
        return jsonify(ret_obj.todict())
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "移动成功"
    ret_obj.data = {"result": {"source_dir": source_dir, "destination": "{}{}".format(DES_DIR_BASE, types),
                               "db3_list": lists_boolean_true}}
    return jsonify(ret_obj.todict())


@api.route("/files/get_log", methods=['POST'])
@verify_json_schema(file_get_log_schema)
@verify_token_auth(allowtokennull=False)
def get_log():
    """
        获取用户操作的日志记录
        ---
        tags:
          - files
        consumes:
          - application/json
        produces:
          - application/json
        parameters:
          - in: body
            name: body
            required: true
            description: JSON 参数.
            schema:
              properties:
                token:
                  type: string
                  description: token.
                  example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
                log_type:
                  type: integer
                  description: 1为提取，2为上传，3为移动，0为其他
                  example: 2
                page:
                  type: integer
                  description: 页码
                  example: 1
                size:
                  type: integer
                  description: 分页大小,最大后台限制 100条数据 默认 10
                  example: 10
        definitions:
          FilesLog:
            type: object
            properties:
              update_time:
                type: string
                description: 日志时间
                example: '2019-12-06 06:05:21'
              file_type:
                type: string
                description: 类型，ref或者meta
                example: ref
              file_num:
                type: integer
                description: 本次操作的文件数量
                example: 5
              explain:
                type: string
                description: 操作时的用户描述
                example: 测试引文上传
              allsize:
                type: integer
                description: 本次操作的文件大小以字节为单位
                example: 12345
              log_json:
                type: object
                description: 本次操作的详细信息,一个json结构的数据,包含每个文件的详细操作信息
                example: {"allsize": 2183431168, "explain": "测试引文上传", "file_num": 2, "failed_up": [], "source_dir": "/RawData/_base_obj_db3/ref", "success_up": [{"name": "zt_bookanjournal_20191108_002.db3", "size": 1091746816}, {"name": "zt_bookanjournal_20191108_003.db3", "size": 1091684352}]}
          ReturnInfoFilesLog:
            type: object
            properties:
              msg_code:
                type: string
                description: SUCCESS 或者 FAILED.
                example: SUCCESS
              msg:
                type: string
                description: 说明文字，帮助找到失败原因
                example: 不能使用get请求
              data:
                type: object
                description: 所有字段信息和总条数
                properties:
                  result:
                    properties:
                      total:
                        type: integer
                        description: 改日志的总条数
                        example: 123
                      list_log:
                        type: array
                        description: 数据列表，一次返回10条，超出范围返回空列表
                        items:
                          $ref: '#/definitions/FilesLog'
        responses:
          200:
            description: OK.
            schema:
              $ref: '#/definitions/ReturnInfoFilesLog'
            examples:
              returninfo: {"msg_code":"SUCCESS","msg":"成功","data":{"result":{"total":123,"list_log":[{},{}]}}}
        :return:
        """
    ret_obj = ReturnInfo()
    jsons = request.json
    log_type = jsons.get("log_type")
    page = jsons.get("page")
    size = jsons.get("size")
    pagination = LogUser.query.filter_by(username=g.user.username, log_type=log_type) \
        .order_by(LogUser.update_time.desc()).paginate(page, per_page=size, error_out=False)
    list_log = []
    for item in pagination.items:
        dicts = {}
        log_json = item.log_json
        update_time = str(item.update_time)
        dicts["update_time"] = update_time
        dicts["log_json"] = log_json
        dicts["file_type"] = item.get_file_type_string()
        dicts["file_num"] = log_json["file_num"]
        dicts["allsize"] = log_json["allsize"]
        dicts["explain"] = log_json["explain"]
        list_log.append(dicts)

    result = {"total": pagination.total, "list_log": list_log}
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "查询日志成功"
    ret_obj.data = {"result": result}
    return jsonify(ret_obj.todict())


@api.route("/files/get_dir_files", methods=['POST'])
@verify_json_schema(get_dir_files_schema)
@verify_token_auth(allowtokennull=False)
def get_dir_files():
    """
    获取要移动目录文件列表
    ---
    tags:
      - files
    consumes:
      - application/json
    produces:
      - application/json
    parameters:
      - in: body
        name: body
        required: true
        description: JSON 参数.
        schema:
          properties:
            token:
              type: string
              description: token.
              example: eyJhbGciOiJIUzUxMiIsImlhdCI6MTU3Mjg0NzY3OSwiZXhwIjoxNTcyODQ4Mjc5fQ.eyJpZCI6MX0.rLbJ_6UQHuHoEA2xjbqtUa28Ogtf2I4JEDa0En0WjgB5pe5L1gT6F5L0RktZuJBE1lBEGT0TAJ1YC7PddwE-Cg
            source_dir:
              type: string
              description: 将要移动的目录，该目录下的db3文件将被移动到/RawData/_base_obj_db3/meta or /RawData/_base_obj_db3/ref 中去
              example: /RawData/_test/db3
    definitions:
      ReturnInfo:
        type: object
        properties:
          msg_code:
            type: string
            description: SUCCESS 或者 FAILED.
            example: SUCCESS
          msg:
            type: string
            description: 说明文字，帮助找到失败原因
            example: 不能使用get请求
          data:
            type: object
            description: 返回的信息全部在data中获取
    responses:
      200:
        description: OK.
        schema:
          $ref: '#/definitions/ReturnInfo'
        examples:
          returninfo: {"msg_code":"SUCCESS","msg":"查询目录成功","data":[{"dbname": "test.db3", "size": 1234},{"dbname": "test.db3", "size": 1234}]}
    :return:
    """
    ret_obj = ReturnInfo()
    jsons = request.json
    source_dir = jsons.get("source_dir")
    source_dir = source_dir.rstrip("/")

    kwargs = {}
    web_hdfs_uri = current_app.config.get("WEB_HDFS")
    kwargs["user.name"] = current_app.config.get("FILES_USER")
    kwargs["op"] = "CREATE"
    kwargs["overwrite"] = False
    requests_session = requests.api
    response = ""
    list_source_complete = []
    try:
        kwargs["op"] = "LISTSTATUS"
        response = requests_session.request("get",
                                            '{}{}'.format(web_hdfs_uri, source_dir),
                                            params=kwargs,
                                            timeout=30,
                                            allow_redirects=False)
        print(response.json())
        if change_hdfs(response):
            ret_obj.msg_code = "FAILED"
            ret_obj.msg = "webhdfs 已切换,请重新访问"
            ret_obj.data = {}
            return jsonify(ret_obj.todict())
        for item in response.json()["FileStatuses"]["FileStatus"]:
            list_source_complete.append({"dbname": item["pathSuffix"], "size": item["length"]})
    except Exception as e:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "需要移动的目录错误,不存在或不是一个目录"
        ret_obj.data = {"errmsg": str(e), "result": jsons}
        return jsonify(ret_obj.todict())
    if not list_source_complete:
        ret_obj.msg_code = "FAILED"
        ret_obj.msg = "目录下没有db3文件"
        ret_obj.data = {"result": jsons}
        return jsonify(ret_obj.todict())
    ret_obj.msg_code = "SUCCESS"
    ret_obj.msg = "查询目录成功"
    ret_obj.data = list_source_complete
    return jsonify(ret_obj.todict())
